Finding AIDS impact in r square

Finding information in data using statistical characteristics #R-squared is a statistical measure of how close the data are to the fitted regression line

Inspired by

# VHS course "R"Kenntnisse um Wissen aus Daten zu gewinnen 2017
library(gapminder)
library(tidyverse)
library(plotly)

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
tidyverse_packages()
 [1] "broom"     "dplyr"     "forcats"   "ggplot2"   "haven"     "httr"     
 [7] "hms"       "jsonlite"  "lubridate" "magrittr"  "modelr"    "purrr"    
[13] "readr"     "readxl"    "stringr"   "tibble"    "rvest"     "tidyr"    
[19] "xml2"      "tidyverse"

Peek into data

PLot data

summary(gapminder)
        country        continent        year         lifeExp           pop           
 Afghanistan:  12   Africa  :624   Min.   :1952   Min.   :23.60   Min.   :6.001e+04  
 Albania    :  12   Americas:300   1st Qu.:1966   1st Qu.:48.20   1st Qu.:2.794e+06  
 Algeria    :  12   Asia    :396   Median :1980   Median :60.71   Median :7.024e+06  
 Angola     :  12   Europe  :360   Mean   :1980   Mean   :59.47   Mean   :2.960e+07  
 Argentina  :  12   Oceania : 24   3rd Qu.:1993   3rd Qu.:70.85   3rd Qu.:1.959e+07  
 Australia  :  12                  Max.   :2007   Max.   :82.60   Max.   :1.319e+09  
 (Other)    :1632                                                                    
   gdpPercap       
 Min.   :   241.2  
 1st Qu.:  1202.1  
 Median :  3531.8  
 Mean   :  7215.3  
 3rd Qu.:  9325.5  
 Max.   :113523.1  
                   
gapminder %>% filter(gdpPercap < 300)
# Print xy plot -----------------------------------------------------------
gapminder <- gapminder %>% mutate(year1950 = year -1950)
ggplot(gapminder, aes(x=year, y=lifeExp)) +geom_line(aes(group = country))

Data wrangling

lets transform the data so that we keep all of a country’s data in one row

  • build nested data.frame
  • access elements of nested data.frame
# Nested data -------------------------------------------------------------
by_country <- gapminder  %>%
  group_by(continent, country) %>%
  nest()
by_country                  # show content of df
str(by_country[1:3,])       # show structure of first 3 rows of grouped and nested df
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   3 obs. of  3 variables:
 $ continent: Factor w/ 5 levels "Africa","Americas",..: 3 4 1
 $ country  : Factor w/ 142 levels "Afghanistan",..: 1 2 3
 $ data     :List of 3
  ..$ :Classes ‘tbl_df’, ‘tbl’ and 'data.frame':    12 obs. of  5 variables:
  .. ..$ year     : int  1952 1957 1962 1967 1972 1977 1982 1987 1992 1997 ...
  .. ..$ lifeExp  : num  28.8 30.3 32 34 36.1 ...
  .. ..$ pop      : int  8425333 9240934 10267083 11537966 13079460 14880372 12881816 13867957 16317921 22227415 ...
  .. ..$ gdpPercap: num  779 821 853 836 740 ...
  .. ..$ year1950 : num  2 7 12 17 22 27 32 37 42 47 ...
  ..$ :Classes ‘tbl_df’, ‘tbl’ and 'data.frame':    12 obs. of  5 variables:
  .. ..$ year     : int  1952 1957 1962 1967 1972 1977 1982 1987 1992 1997 ...
  .. ..$ lifeExp  : num  55.2 59.3 64.8 66.2 67.7 ...
  .. ..$ pop      : int  1282697 1476505 1728137 1984060 2263554 2509048 2780097 3075321 3326498 3428038 ...
  .. ..$ gdpPercap: num  1601 1942 2313 2760 3313 ...
  .. ..$ year1950 : num  2 7 12 17 22 27 32 37 42 47 ...
  ..$ :Classes ‘tbl_df’, ‘tbl’ and 'data.frame':    12 obs. of  5 variables:
  .. ..$ year     : int  1952 1957 1962 1967 1972 1977 1982 1987 1992 1997 ...
  .. ..$ lifeExp  : num  43.1 45.7 48.3 51.4 54.5 ...
  .. ..$ pop      : int  9279525 10270856 11000948 12760499 14760787 17152804 20033753 23254956 26298373 29072015 ...
  .. ..$ gdpPercap: num  2449 3014 2551 3247 4183 ...
  .. ..$ year1950 : num  2 7 12 17 22 27 32 37 42 47 ...
by_country$data[[1]]        # show data of first row
by_country$data[1]          # show data of first row
[[1]]
by_country$data[[1]][[2]]   # show  contents of second column 
 [1] 28.801 30.332 31.997 34.020 36.088 38.438 39.854 40.822 41.674 41.763 42.129
[12] 43.828
by_country$data[[1]][2]     # show second column
  • [ returns a list
  • [[ returns content of list

a good explanation can be found at: http://r4ds.had.co.nz/vectors.html#lists

structure of dataframe

The column data is a list of data frames. Therefore, we have now a row per country and all data of that country in a dataframe in one column.

In a grouped dataframe each row is an oberservation, in a nested dataframe each row is a group, in this case, a group of a country’s observations.

Build a model

Lets build a model for each country, lifeExp ~ year

# Fit models --------------------------------------------------------------
country_model <- function(df){
  lm(lifeExp  ~  year1950, data=df)  # use year1950 because the absolute value is not important
}
models <- by_country %>%
  mutate(
    model = map(data, country_model)
  )
models
lm(lifeExp  ~  year1950, data=by_country$data[[1]]) 

Call:
lm(formula = lifeExp ~ year1950, data = by_country$data[[1]])

Coefficients:
(Intercept)     year1950  
    29.3566       0.2753  
models$model[1]
[[1]]

Call:
lm(formula = lifeExp ~ year1950, data = df)

Coefficients:
(Intercept)     year1950  
    29.3566       0.2753  

Combine data wrangling and modell building

# Put it all together -----------------------------------------------------
by_country <- gapminder  %>%
  group_by(continent, country) %>%
  nest() %>%  
  mutate(
    model = map(data, country_model)
  )
by_country

Get the model data in a tidy form using the broom package

models <- models %>%
  mutate(
    glance  = map(model, broom::glance),        # Construct a single row summary "glance" of a model
    rsq     = glance %>% map_dbl("r.squared"),  # note the pipe within mutate(...)
    tidy    = map(model, broom::tidy),          # Tidy the result of a test into a summary data.frame
    augment = map(model, broom::augment)
  )
models
models$glance[1]
[[1]]
models$rsq[1]
[1] 0.9477123
models$tidy[1]
[[1]]
models$augment[1]
[[1]]
NA

Investigate how well the model fits

models %>% 
  ggplot(aes(rsq, country)) +
  geom_point(aes(colour = continent)) 

# source("gapminderShiny.R")

is the plot clear? how could it be improved?

ggplot orders categorical variables alphabetically

models %>% 
  ggplot(aes(rsq, reorder(country, rsq))) +
  geom_point(aes(colour = continent)) 

Find the countries with the worst fit

  models %>% filter((rsq<0.1 & rsq>0))  %>% unnest(rsq)  %>% top_n(6,rsq) %>% unnest(data) %>% 
    ggplot(aes(year, lifeExp)) +
    geom_line(aes( alpha = 1/3))  +
    facet_wrap(~country)

NA

How much did the countries improve life expectancy over time

# Unnest data -------------------------------------------------------------
unnest(models, data)
unnest(models, glance, .drop = TRUE) 
unnest(models, tidy)
# Plot data frame ---------------------------------------------------------
plotLife <- models %>%
  unnest(tidy) %>%
  select(continent, country, term, estimate, rsq) %>%
  spread(term, estimate) %>%
  ggplot(aes(`(Intercept)`,year1950))+
  geom_point(aes(colour = continent, size = rsq, fill = country)) +
  geom_smooth(se=FALSE) +
  xlab("Life expectancy (1950)") +
  ylab("Yearly improvement") +
  scale_size_area() + guides(fill=FALSE)
ggplotly(plotLife, tooltip = c("year1950", "country"))
`geom_smooth()` using method = 'loess'

where are the exeptions

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).

LS0tCnRpdGxlOiAiR2FwbWluZGVyIGZvciBWSFMgMS8yMDE3IgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICBodG1sX25vdGVib29rOiBkZWZhdWx0Ci0tLQoKIyBGaW5kaW5nIEFJRFMgaW1wYWN0IGluIHIgc3F1YXJlCgpGaW5kaW5nIGluZm9ybWF0aW9uIGluIGRhdGEgdXNpbmcgc3RhdGlzdGljYWwgY2hhcmFjdGVyaXN0aWNzIAojKipSLXNxdWFyZWQqKiBpcyBhIHN0YXRpc3RpY2FsIG1lYXN1cmUgb2YgaG93IGNsb3NlIHRoZSBkYXRhIGFyZSB0byB0aGUgZml0dGVkIHJlZ3Jlc3Npb24gbGluZQoKKipJbnNwaXJlZCBieSAqKgoKLSBURUQgdGFsayBvZiAgKipIYW5zIFJvc2xpbmcqKjogTGV0IG15IGRhdGFzZXQgY2hhbmdlIHlvdXIgbWluZHNldApodHRwczovL3d3dy50ZWQuY29tL3RhbGtzL2hhbnNfcm9zbGluZ19hdF9zdGF0ZSN0LTExNzY0MDcKCi0gKipIYWRsZXkgV2lja2hhbSoqIE1hbmFnaW5nIG1hbnkgbW9kZWxzIHdpdGggUiBodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PXJ6M19GRFZ0OWVnIAoKCgoKYGBge3J9CiMgVkhTIGNvdXJzZSAiUiJLZW5udG5pc3NlIHVtIFdpc3NlbiBhdXMgRGF0ZW4genUgZ2V3aW5uZW4gMjAxNwoKbGlicmFyeShnYXBtaW5kZXIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHBsb3RseSkKdGlkeXZlcnNlX3BhY2thZ2VzKCkKYGBgCgojIyBQZWVrIGludG8gZGF0YQojIyMgUExvdCBkYXRhCiAKYGBge3J9CnN1bW1hcnkoZ2FwbWluZGVyKQpnYXBtaW5kZXIgJT4lIGZpbHRlcihnZHBQZXJjYXAgPCAzMDApCiMgUHJpbnQgeHkgcGxvdCAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKCmdhcG1pbmRlciA8LSBnYXBtaW5kZXIgJT4lIG11dGF0ZSh5ZWFyMTk1MCA9IHllYXIgLTE5NTApCmdncGxvdChnYXBtaW5kZXIsIGFlcyh4PXllYXIsIHk9bGlmZUV4cCkpICtnZW9tX2xpbmUoYWVzKGdyb3VwID0gY291bnRyeSkpCgpgYGAKCiMjIyBEYXRhIHdyYW5nbGluZwpsZXRzIHRyYW5zZm9ybSB0aGUgZGF0YSBzbyB0aGF0IHdlIGtlZXAgYWxsIG9mIGEgY291bnRyeSdzIGRhdGEgaW4gb25lIHJvdwoKLSBidWlsZCBuZXN0ZWQgZGF0YS5mcmFtZQotIGFjY2VzcyBlbGVtZW50cyBvZiBuZXN0ZWQgZGF0YS5mcmFtZQoKYGBge3J9CgojIE5lc3RlZCBkYXRhIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCmJ5X2NvdW50cnkgPC0gZ2FwbWluZGVyICAlPiUKICBncm91cF9ieShjb250aW5lbnQsIGNvdW50cnkpICU+JQogIG5lc3QoKQoKYnlfY291bnRyeSAgICAgICAgICAgICAgICAgICMgc2hvdyBjb250ZW50IG9mIGRmCnN0cihieV9jb3VudHJ5WzE6MyxdKSAgICAgICAjIHNob3cgc3RydWN0dXJlIG9mIGZpcnN0IDMgcm93cyBvZiBncm91cGVkIGFuZCBuZXN0ZWQgZGYKYnlfY291bnRyeSRkYXRhW1sxXV0gICAgICAgICMgc2hvdyBkYXRhIG9mIGZpcnN0IHJvdwpieV9jb3VudHJ5JGRhdGFbMV0gICAgICAgICAgIyBzaG93IGRhdGEgb2YgZmlyc3Qgcm93CmJ5X2NvdW50cnkkZGF0YVtbMV1dW1syXV0gICAjIHNob3cgIGNvbnRlbnRzIG9mIHNlY29uZCBjb2x1bW4gCmJ5X2NvdW50cnkkZGF0YVtbMV1dWzJdICAgICAjIHNob3cgc2Vjb25kIGNvbHVtbgpgYGAKCgotIFsgcmV0dXJucyBhIGxpc3QKLSBbWyByZXR1cm5zIGNvbnRlbnQgb2YgbGlzdAoKYSBnb29kIGV4cGxhbmF0aW9uIGNhbiBiZSBmb3VuZCBhdDogaHR0cDovL3I0ZHMuaGFkLmNvLm56L3ZlY3RvcnMuaHRtbCNsaXN0cyAKCiMjIyBzdHJ1Y3R1cmUgb2YgZGF0YWZyYW1lCgpUaGUgY29sdW1uICoqZGF0YSoqIGlzIGEgbGlzdCBvZiBkYXRhIGZyYW1lcy4gVGhlcmVmb3JlLCB3ZSBoYXZlIG5vdyBhIHJvdyBwZXIgY291bnRyeSBhbmQgYWxsIGRhdGEgb2YgdGhhdCBjb3VudHJ5IGluIGEgZGF0YWZyYW1lIGluICoqb25lKiogY29sdW1uLgoKSW4gYSBncm91cGVkIGRhdGFmcmFtZSAqKmVhY2ggcm93IGlzIGFuIG9iZXJzZXJ2YXRpb24qKiwgaW4gYSBuZXN0ZWQgZGF0YWZyYW1lICoqZWFjaCByb3cgaXMgYSBncm91cCoqLCBpbiB0aGlzIGNhc2UsIGEgZ3JvdXAgb2YgYSBjb3VudHJ54oCZcyBvYnNlcnZhdGlvbnMuCgoKCiMjIEJ1aWxkIGEgbW9kZWwKTGV0cyBidWlsZCBhIG1vZGVsIGZvciBlYWNoIGNvdW50cnksIGxpZmVFeHAgfiAgeWVhcgoKCmBgYHtyfQoKIyBGaXQgbW9kZWxzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpjb3VudHJ5X21vZGVsIDwtIGZ1bmN0aW9uKGRmKXsKICBsbShsaWZlRXhwICB+ICB5ZWFyMTk1MCwgZGF0YT1kZikgICMgdXNlIHllYXIxOTUwIGJlY2F1c2UgdGhlIGFic29sdXRlIHZhbHVlIGlzIG5vdCBpbXBvcnRhbnQKfQptb2RlbHMgPC0gYnlfY291bnRyeSAlPiUKICBtdXRhdGUoCiAgICBtb2RlbCA9IG1hcChkYXRhLCBjb3VudHJ5X21vZGVsKQogICkKbW9kZWxzCmxtKGxpZmVFeHAgIH4gIHllYXIxOTUwLCBkYXRhPWJ5X2NvdW50cnkkZGF0YVtbMV1dKSAKbW9kZWxzJG1vZGVsWzFdCgpgYGAKCiMjIyBDb21iaW5lIGRhdGEgd3JhbmdsaW5nIGFuZCBtb2RlbGwgYnVpbGRpbmcKCmBgYHtyfQoKIyBQdXQgaXQgYWxsIHRvZ2V0aGVyIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpieV9jb3VudHJ5IDwtIGdhcG1pbmRlciAgJT4lCiAgZ3JvdXBfYnkoY29udGluZW50LCBjb3VudHJ5KSAlPiUKICBuZXN0KCkgJT4lICAKICBtdXRhdGUoCiAgICBtb2RlbCA9IG1hcChkYXRhLCBjb3VudHJ5X21vZGVsKQogICkKCmJ5X2NvdW50cnkKYGBgCgoKCiMjIEdldCB0aGUgbW9kZWwgZGF0YSBpbiBhIHRpZHkgZm9ybSB1c2luZyB0aGUgKipicm9vbSoqIHBhY2thZ2UKCmBgYHtyfQptb2RlbHMgPC0gbW9kZWxzICU+JQogIG11dGF0ZSgKICAgIGdsYW5jZSAgPSBtYXAobW9kZWwsIGJyb29tOjpnbGFuY2UpLCAgICAgICAgIyBDb25zdHJ1Y3QgYSBzaW5nbGUgcm93IHN1bW1hcnkgImdsYW5jZSIgb2YgYSBtb2RlbAogICAgcnNxICAgICA9IGdsYW5jZSAlPiUgbWFwX2RibCgici5zcXVhcmVkIiksICAjIG5vdGUgdGhlIHBpcGUgd2l0aGluIG11dGF0ZSguLi4pCiAgICB0aWR5ICAgID0gbWFwKG1vZGVsLCBicm9vbTo6dGlkeSksICAgICAgICAgICMgVGlkeSB0aGUgcmVzdWx0IG9mIGEgdGVzdCBpbnRvIGEgc3VtbWFyeSBkYXRhLmZyYW1lCiAgICBhdWdtZW50ID0gbWFwKG1vZGVsLCBicm9vbTo6YXVnbWVudCkKICApCm1vZGVscwptb2RlbHMkZ2xhbmNlWzFdCm1vZGVscyRyc3FbMV0KbW9kZWxzJHRpZHlbMV0KbW9kZWxzJGF1Z21lbnRbMV0KYGBgCgojIyMgSW52ZXN0aWdhdGUgaG93IHdlbGwgdGhlIG1vZGVsIGZpdHMgCgoKYGBge3J9Cgptb2RlbHMgJT4lIAogIGdncGxvdChhZXMocnNxLCBjb3VudHJ5KSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IGNvbnRpbmVudCkpIAojIHNvdXJjZSgiZ2FwbWluZGVyU2hpbnkuUiIpCmBgYAoKaXMgdGhlIHBsb3QgY2xlYXI/IGhvdyBjb3VsZCBpdCBiZSBpbXByb3ZlZD8KCgoKZ2dwbG90IG9yZGVycyBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgYWxwaGFiZXRpY2FsbHkgCgpgYGB7cn0KCm1vZGVscyAlPiUgCiAgZ2dwbG90KGFlcyhyc3EsIHJlb3JkZXIoY291bnRyeSwgcnNxKSkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBjb250aW5lbnQpKSAKCmBgYAoKIyMjIEZpbmQgdGhlIGNvdW50cmllcyB3aXRoIHRoZSB3b3JzdCBmaXQKCgpgYGB7cn0KCiAgbW9kZWxzICU+JSBmaWx0ZXIoKHJzcTwwLjEgJiByc3E+MCkpICAlPiUgdW5uZXN0KHJzcSkgICU+JSB0b3Bfbig2LHJzcSkgJT4lIHVubmVzdChkYXRhKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHllYXIsIGxpZmVFeHApKSArCiAgICBnZW9tX2xpbmUoYWVzKCBhbHBoYSA9IDEvMykpICArCiAgICBmYWNldF93cmFwKH5jb3VudHJ5KQogIApgYGAKCiMgSG93IG11Y2ggZGlkIHRoZSBjb3VudHJpZXMgaW1wcm92ZSBsaWZlIGV4cGVjdGFuY3kgb3ZlciB0aW1lCgoKYGBge3J9CgojIFVubmVzdCBkYXRhIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCnVubmVzdChtb2RlbHMsIGRhdGEpCnVubmVzdChtb2RlbHMsIGdsYW5jZSwgLmRyb3AgPSBUUlVFKSAKdW5uZXN0KG1vZGVscywgdGlkeSkKCiMgUGxvdCBkYXRhIGZyYW1lIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKCnBsb3RMaWZlIDwtIG1vZGVscyAlPiUKICB1bm5lc3QodGlkeSkgJT4lCiAgc2VsZWN0KGNvbnRpbmVudCwgY291bnRyeSwgdGVybSwgZXN0aW1hdGUsIHJzcSkgJT4lCiAgc3ByZWFkKHRlcm0sIGVzdGltYXRlKSAlPiUKICBnZ3Bsb3QoYWVzKGAoSW50ZXJjZXB0KWAseWVhcjE5NTApKSsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBjb250aW5lbnQsIHNpemUgPSByc3EsIGZpbGwgPSBjb3VudHJ5KSkgKwogIGdlb21fc21vb3RoKHNlPUZBTFNFKSArCiAgeGxhYigiTGlmZSBleHBlY3RhbmN5ICgxOTUwKSIpICsKICB5bGFiKCJZZWFybHkgaW1wcm92ZW1lbnQiKSArCiAgc2NhbGVfc2l6ZV9hcmVhKCkgKyBndWlkZXMoZmlsbD1GQUxTRSkKZ2dwbG90bHkocGxvdExpZmUsIHRvb2x0aXAgPSBjKCJ5ZWFyMTk1MCIsICJjb3VudHJ5IikpCgoKCmBgYAojIyB3aGVyZSBhcmUgdGhlIGV4ZXB0aW9ucwoKYGBge3J9Cgp1bm5lc3QobW9kZWxzLCBhdWdtZW50KSAjIHVzaW5nIHRoZSB1bm5lc3Qgd2l0aCBvbmUgYXVnbWVudCBhcmd1bWVudCBrZWVwcyB0aGUgZ3JvdXBpbmcgdmFyaWFibGVzIGFuZCBhdWdtZW50IAoKbW9kZWxzICU+JSB1bm5lc3QoYXVnbWVudCkgJT4lIAogIGdncGxvdChhZXMoeWVhcjE5NTAsIC5yZXNpZCkpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gY291bnRyeSksIGFscGhhID0gMS8zKSArCiAgZ2VvbV9zbW9vdGgoc2UgPSBGQUxTRSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG91ciA9ICJ3aGl0ZSIpICsKICBmYWNldF93cmFwKH5jb250aW5lbnQsIHNjYWxlcyA9ICJmcmVlX3kiKSAKCgpgYGAKCkFkZCBhIG5ldyBjaHVuayBieSBjbGlja2luZyB0aGUgKkluc2VydCBDaHVuayogYnV0dG9uIG9uIHRoZSB0b29sYmFyIG9yIGJ5IHByZXNzaW5nICpDbWQrT3B0aW9uK0kqLgoKV2hlbiB5b3Ugc2F2ZSB0aGUgbm90ZWJvb2ssIGFuIEhUTUwgZmlsZSBjb250YWluaW5nIHRoZSBjb2RlIGFuZCBvdXRwdXQgd2lsbCBiZSBzYXZlZCBhbG9uZ3NpZGUgaXQgKGNsaWNrIHRoZSAqUHJldmlldyogYnV0dG9uIG9yIHByZXNzICpDbWQrU2hpZnQrSyogdG8gcHJldmlldyB0aGUgSFRNTCBmaWxlKS4=